﻿namespace Lite.Messaging.Msmq
{
    using System.Messaging;

    /// <summary>
    /// Implements the IMessage interface for MSMQ.
    /// </summary>
    internal partial class MsmqMessage
    {
        private readonly object parameterValuesLockObject = new object();

        protected MsmqMessage(Message message)
        {
            Message = message;
            this.ParameterValues = (MsmqMessageValueDictionary)Message.Body;
        }

        protected MsmqMessage(Message message, MsmqMessageValueDictionary parameterValues)
        {
            Message = message;
            this.ParameterValues = parameterValues;
            Message.Body = parameterValues;
        }

        /// <summary>
        /// Gets the MSMQ message around which this instance wraps.
        /// </summary>
        public Message Message
        {
            get;
            private set;
        }

        protected MsmqMessageValueDictionary ParameterValues
        {
            get;
            private set;
        }

        public void SetValue<T>(IParameter<T> parameter, T value)
        {
            lock (parameterValuesLockObject)
            {
                ParameterValues[parameter.Id] = value;
            }
        }

        public void ClearValues()
        {
            lock (parameterValuesLockObject)
            {
                ParameterValues.Clear();
            }
        }
    }

    internal partial class MsmqMessage
        : IMessage
    {
        public object ConversationId
        {
            get
            {
                return Message.CorrelationId;
            }
        }

        public string Label
        {
            get
            {
                return Message.Label;
            }

            set
            {
                Message.Label = value;
            }
        }

        public T GetValue<T>(IParameter<T> parameter)
        {
            lock (parameterValuesLockObject)
            {
                if (!this.ParameterValues.ContainsKey(parameter.Id))
                {
                    throw new ParameterNotFoundException<T>(parameter);
                }

                object parameterValue = this.ParameterValues[parameter.Id];

                return (T)parameterValue;
            }
        }
        
        public void CopyTo(ISendMessage message)
        {
            throw new IncompatibleMessageTypeException();
        }

        public bool CanCopyTo(ISendMessage message)
        {
            return false;
        }

        public bool HasValue<T>(IParameter<T> parameter)
        {
            lock (parameterValuesLockObject)
            {
                return this.ParameterValues.ContainsKey(parameter.Id);
            }
        }
    }
}
